import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Observable } from 'rxjs';
import { Reflector } from '@nestjs/core';
import { JwtService } from '@nestjs/jwt';
import { ConfigService } from '@nestjs/config';

/**
 * @breif: 角色守卫，与装饰器结合，对接口做角色权限区分。首先角色以数组的形式保存在token中，所以需要jwt解析token取出当前用户的角色。
 * 第二步获取装饰器传入的接口所需权限字符，如果装饰器没传入角色字符则表示该接口不需要角色对比，否则的话两者对比。传入的字符是否包含当前登录用户角色，如果包含则放开，否则返回false、
 * @return {*}
 */
@Injectable()
export class RoleGuard implements CanActivate {
  constructor(
    private readonly reflector: Reflector,
    private readonly jwtService: JwtService,
    private readonly configService: ConfigService,
  ) { }
  canActivate(
    context: ExecutionContext,
  ): boolean | Promise<boolean> | Observable<boolean> {
    const request = context.switchToHttp().getRequest<Request>();
    const defRoles = this.reflector.get<string[]>(
      'roles',
      context.getHandler(),
    );
    // @ts-ignore
    if (defRoles && request.headers?.authorization) {
      // @ts-ignore
      const token = request.headers.authorization.split('Bearer ')[1];
      const decoded = this.jwtService.verify(token, {
        secret: this.configService.get<string>('SECRET_KEY'),
      });
      const roles = decoded.roles;
      let flag = false;
      if (Array.isArray(roles)) {
        roles.forEach((element) => {
          if (defRoles.includes(element)) {
            flag = true;
          }
        });
      } else {
        if (defRoles.includes(roles)) {
          flag = true;
        }
      }

      return flag;
    } else {
      return true;
    }
  }
}
